package com.freestyle.redis.expire;

import com.freestyle.netty.easynetty.common.Utils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.time.Duration;

/**
 * Redis失效增强服务
 * Created by rocklee on 2022/2/5 10:37
 */
@Component
public class RedisExpirationTemplate<K,V> implements InitializingBean {
  @Resource
  private RedisTemplate<Object,Object> redisTemplate;
  @Resource
  private RedisKeyExpirationListener redisKeyExpirationListener;
  private static final String EXP_KEY_LIST_PREFIX="KEY-EXP-LIST:";
  private static final String EXP_KEY_SET_PREFIX="KEY-EXP-SET:";
  private static final String EXP_KEY_MAP_PREFIX="KEY-EXP-MAP:";


  public Long listAdd(K k, V v, Duration duration){
    redisTemplate.opsForValue().set(EXP_KEY_LIST_PREFIX+ Utils.toJsonString(new KVDto<>(k, v)),"",duration);
    return redisTemplate.opsForList().rightPush(k,v);
  }
  public Long listRemove(K k,V v){
    redisTemplate.delete(EXP_KEY_LIST_PREFIX+ Utils.toJsonString(new KVDto<>(k, v)));
    return redisTemplate.opsForList().remove(k,1,v);
  }
  public V listRPop(K k){
    V v= (V) redisTemplate.opsForList().rightPop(k);
    if (v!=null) {
      redisTemplate.delete(EXP_KEY_LIST_PREFIX + Utils.toJsonString(new KVDto<>(k, v)));
    }
    return v;
  }
  public V listLPop(K k){
    V v= (V) redisTemplate.opsForList().leftPop(k);
    if (v!=null) {
      redisTemplate.delete(EXP_KEY_LIST_PREFIX + Utils.toJsonString(new KVDto<>(k, v)));
    }
    return v;
  }
  public Long setAdd(K k,V v,Duration duration){
    redisTemplate.opsForValue().set(EXP_KEY_SET_PREFIX+ Utils.toJsonString(new KVDto<>(k, v)),"",duration);
    return redisTemplate.opsForSet().add(k,v);
  }
  public void setAdd(Duration duration,K k,V ...v){
    for (V vv:v){
      setAdd(k,vv,duration);
    }
  }
  public V setPop(K k){
    V v = (V) redisTemplate.opsForSet().pop(k);
    if (v!=null){
      redisTemplate.delete(EXP_KEY_SET_PREFIX + Utils.toJsonString(new KVDto<>(k, v)));
    }
    return v;
  }
  public Long setRemove(K k,V...v){
    for (V vv:v){
      redisTemplate.delete(EXP_KEY_SET_PREFIX + Utils.toJsonString(new KVDto<>(k, vv)));
    }
    return redisTemplate.opsForSet().remove(k,v);
  }
  public void mapAdd(String name,K k,V v,Duration duration){
    redisTemplate.opsForHash().put(name,k,v);
    redisTemplate.opsForValue().set(EXP_KEY_MAP_PREFIX+ Utils.toJsonString(new KVDto<>(name, k)),"",duration);
  }
  public Long mapRemove(String name,K... k){
    for (K kk:k){
      redisTemplate.delete(EXP_KEY_MAP_PREFIX + Utils.toJsonString(new KVDto<>(name, k)));
    }
    return redisTemplate.opsForHash().delete(name,k);
  }
  public RedisTemplate getTemplate(){
    return redisTemplate;
  }
  @Override
  public void afterPropertiesSet() throws Exception {
    redisKeyExpirationListener.addProcess(msg->{
      String rawStr=null;
      //byte[] content=null;
      try(ByteArrayInputStream bis=new ByteArrayInputStream(msg.getBody());
          ObjectInputStream ois=new ObjectInputStream(bis)
      ){
        rawStr= (String) ois.readObject();
      } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
      }
      if (!rawStr.contains(":"))return;
      //String rawStr=new String(content,"utf-8");
      String[] items=rawStr.split(":",2);
      KVDto kvDto=Utils.fromJson(items[1],KVDto.class);
      if (rawStr.startsWith(EXP_KEY_LIST_PREFIX)){
        redisTemplate.opsForList().remove(kvDto.getK(),1,kvDto.getV());
      }
      else if (rawStr.startsWith(EXP_KEY_SET_PREFIX)){
        redisTemplate.opsForSet().remove(kvDto.getK(),1,kvDto.getV());
      }
      else if (rawStr.startsWith(EXP_KEY_MAP_PREFIX)){
        redisTemplate.opsForHash().delete(kvDto.getK(),1,kvDto.getV());
      }
    });
  }
}
